package com.ylr.base.common.tool;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ylr.base.common.constant.Constant;
import com.ylr.base.common.enums.ResultEnum;
import com.ylr.base.common.exception.YlrException;
import com.ylr.base.common.vo.BaseVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-03-15 13:51:00
 * className: PageQuery Mybatis-Plus分页条件构造工具类
 * version: 1.0
 * description:
 */
public class PageQuery {

    private static final Logger log = LoggerFactory.getLogger(PageQuery.class);

    /**
     * 构造mp分页查询对象
     * @param baseVo 存储分页查询条件的Vo对象
     * @return 分页对象
     */
    public static <T> Page<T> initPage(BaseVo baseVo) {
        Page<T> page = new Page<>(baseVo.getPageNo(), baseVo.getPageSize());

        if (checkField(baseVo.getField())) {
            log.error("系统发生sql注入，请注意，请务必立即处理");
            throw new YlrException(ResultEnum.SQL_FAIL);
        }

        // 驼峰转下划线
        String field = toUnderlineCase(baseVo.getField());

        if (Constant.DESCENDING.equals(baseVo.getOrder())) {
            page.addOrder(OrderItem.desc(field));
        } else {
            page.addOrder(OrderItem.asc(field));
        }
        return page;
    }

    /**
     * 正则校验字段是否存在sql注入
     *
     * @param field 待检验字符串
     * @return 校验结果[false-没有注入 true-发生注入]
     */
    public static boolean checkField(String field) {
        // 替换字符串
        field = field.replaceAll(".*([';]+|(--)+).*", "");
        // 正则表达式
        String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"
                + "(\b(select|update|and|or|delete|insert|truncate|char|into|substr|ascii|declare|exec|count|master|drop|execute)\b)";
        // 生成校验规则
        Pattern pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
        // 正则校验
        Matcher matcher = pattern.matcher(field);
        // 返回校验结果
        return matcher.find();
    }

    /**
     * 驼峰 转 下划线
     * userName   ---->  user_name
     * user_name  ---->  user_name
     * <p>
     * 注意:
     *  只处理参数字符串中大写字符，如将'A-Z'转换成对应的'a-z'，并在字符前面添加'下划线'
     *
     * @param camelCaseStr 驼峰字符串
     * @return 带下滑线的String
     */
    private static String toUnderlineCase(String camelCaseStr) {
        // 将驼峰字符串转换成数组
        StringBuilder sb = new StringBuilder();
        //处理字符串
        for (char c : camelCaseStr.toCharArray()) {
            if (c >= 65 && c <= 90) {
                c += 32;
                sb.append("_").append(c);
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}
